﻿using System;
using System.Collections;
using System.Speech.Recognition.SrgsGrammar;
using System.Speech.Recognition;
using System.Windows.Forms;
using System.IO;
using System.Reflection;
using System.Resources;
using Alfred.Ressource;

namespace Alfred
{
	class ASR
	{
		public SpeechRecognitionEngine ASREngine;
		public Alfred alfred { get; set; }

		private Label recoText;
		private Label commandText;
		
		private Grammar grammar1;
		private DictationGrammar grammar2;

		private FFT fft;

		private string lastCommand;

		public ASR(ref Label recoText, ref Label commandText)
		{
			this.recoText = recoText;
			this.commandText = commandText;
			alfred = new Alfred();

			configEngine();
			StartEngine();
		}

		public void FillGrammar()
		{
			XML.AddToXml("film", Allocine.GetAllMovieListString());
			XML.AddToXml("cinema", Allocine.GetAllCinemaListString());
			XML.AddToXml("piece", Device.GetAllDeviceListString());
			XML.AddToXml("artist", new Playlist().artistList);
			XML.AddToXml("genre", new Playlist().genreList);
			XML.AddToXml("mode", Scenario.getScenarioStringList());
		}

		public void configEngine()
		{
			FillGrammar();
			ASREngine = new SpeechRecognitionEngine();
			ASREngine.SetInputToDefaultAudioDevice();
			SrgsDocument xmlGrammar = new SrgsDocument(Paths.path_grammar);
            grammar1 = new Grammar(xmlGrammar);
			grammar2 = new DictationGrammar();
		}

		public void StartEngine()
		{
			ASREngine.LoadGrammar(grammar1);
			ASREngine.SpeechRecognized += ASREngine_SpeechRecognized;
			ASREngine.SpeechRecognitionRejected += ASREngine_SpeechRecognitionRejected;
			ASREngine.SpeechHypothesized += ASREngine_SpeechHypothesized;
			ASREngine.MaxAlternates = 4;
		}

		public void StartEngineDictation()
		{
			ASREngine.LoadGrammar(grammar2);
			ASREngine.SpeechRecognized += ASREngine_SpeechRecognizedRappel;
			ASREngine.SpeechRecognitionRejected += ASREngine_SpeechRecognitionRejected;
			ASREngine.SpeechHypothesized += ASREngine_SpeechHypothesized;
			ASREngine.RecognizeAsync(RecognizeMode.Multiple);
		}

		private void ASREngine_SpeechHypothesized(object sender, SpeechHypothesizedEventArgs e)
		{
            recoText.Text = "Hypothèse : " + e.Result.Text;
		}

		private void ASREngine_SpeechRecognitionRejected(object sender, SpeechRecognitionRejectedEventArgs e)
		{
            recoText.Text = "Reconnaissance impossible";
		}

		private void ASREngine_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {
            fft = new FFT(Paths.path_temp_wav);
            if (!fft.isSignalOk(e.Result.Audio, e.Result.Audio.StartTime, e.Result.Alternates[0].Confidence))
			{
				commandText.Text = "Bruit";
				return;
			}

			recoText.Text = e.Result.Text;
			string baseCommand = e.Result.Semantics["alfred"].Value.ToString();
			commandText.Text = baseCommand;

            Execute(baseCommand, e);
		}

		private void ASREngine_SpeechRecognizedRappel(object sender, SpeechRecognizedEventArgs e)
		{
            if (!fft.isSignalOk(e.Result.Audio, e.Result.Audio.StartTime, e.Result.Alternates[0].Confidence))
            {
                commandText.Text = "Bruit";
                return;
            }

			ASREngine.Dispose();
			configEngine();
			StartEngine();
		}

		public void Execute(string command, SpeechRecognizedEventArgs e)
		{
			alfred.result = e.Result;
			lastCommand = command;

			// Dynamic call to alfred method matching command name
			MethodInfo methodInfo = typeof(Alfred).GetMethod(command);
			methodInfo.Invoke(alfred, null);

			string alfredResponse = ReadResourceValue("Ressource/AlfredDialog.resx", command);
			if (alfredResponse != "")
				alfred.Speak(alfredResponse);
		}

		public string ReadResourceValue(string file, string key)
		{
			string resourceValue = string.Empty;
			try
			{
				string filePath = System.AppDomain.CurrentDomain.BaseDirectory.ToString();
				ResourceManager resourceManager = ResourceManager.CreateFileBasedResourceManager(file, filePath, null);
				resourceValue = resourceManager.GetString(key);
			}
			catch (Exception ex)
			{
				resourceValue = "";
			}
			return resourceValue;
		}
	}
}
